﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using ENICHIUSURA.Utils;
using Logging;
using System.Configuration;
using System.Runtime.Serialization.Formatters.Binary;

namespace ENICHIUSURA
{
    class Automation
    {
        string searchPath1 = ConfigurationManager.AppSettings["FirstSearchPath"];
        string searchPath2 = ConfigurationManager.AppSettings["SecondSearchPath"];
        
        string outputFilePath = ConfigurationManager.AppSettings["OutputFilePath"];
        string outputFileName = ConfigurationManager.AppSettings["OutputFilename"];
        
        bool foundFile = false;
        DataColumn statusColumn ;
        DataColumn destinationPath ;
        DataColumn sourcePath ;

        IEnumerable<FileInfo> filesInfo = null;
        Dictionary<int, List<FileInfo>> filesDict = null;
        public Automation()
        {
        }
        /// <summary>
        ///  Receives a dataTable with the excel informations and loops each record
        /// </summary>
        /// <param name="dt">First row in dt.Rows is the header</param>
        public string Run(DataTable dt)
        {
            AddNewColumns(dt);
            DataColumn dateColumn = dt.Columns["DATA1"]; 
            DataColumn codVelColumn = dt.Columns["COD_VEL"];
            DataColumn contrattoColumn = dt.Columns["CONTRATTO"];
            
           // fileList = FileUtils.BuildFileList(searchPath2); //O(n) for each record; can do better with dictionary
           
           //filesInfo = SerializedIndex(ConfigurationManager.AppSettings["SerializedDictPath"]);//good for testing; find a solution to use rootDirectory's last modified time as Timestamp
           //filesDict = FileUtils.BuildDictionaryFromFilesList(filesInfo); 
            
           filesDict = BuildDictionary(searchPath2); //time consuming for indexing but O(1) for get :D ..indexing every time
        

           if (dateColumn != null)
           {
               foreach (DataRow row in dt.Rows)
               {
                   int index = dt.Rows.IndexOf(row);
                   foundFile = false;
                   if (index == 0) 
                   {
                       continue;
                   }
                   else if (row[dateColumn] != DBNull.Value && row[codVelColumn] != DBNull.Value && row[contrattoColumn] != DBNull.Value)
                   {
                       if (SearchFirstPathHardC(row) == true) //ugly..the possible fpath can have multiple forms
                           continue;                          // could use indexing also

                       else  // for the second path we use the dictionary of Files
                       {
                           #region SearchWithDictionary
                           if (filesDict != null)
                           {
                               if (row[codVelColumn] != DBNull.Value)
                               {
                                   int key = FileUtils.ParseCodVel(row[codVelColumn].ToString());//DbNull.ToString() == ""
                                   if (filesDict.ContainsKey(key))
                                   {
                                       FileInfo current = null;
                                       List<FileInfo> fis = filesDict[key];
                                       foreach (FileInfo item in fis) //all the debts of the current debitor
                                       {
                                           current = item;
                                           if (CheckParentDirs(item, row[codVelColumn].ToString(), row[dateColumn].ToString()))
                                           {
                                               string destFilePath = BuildDestionationPath(outputFilePath, row[dateColumn].ToString(), row[contrattoColumn].ToString(), row[codVelColumn].ToString(), item.Extension);
                                               if (destFilePath != "")
                                               {
                                                   FileUtils.CopyRenamed(item.Directory.FullName + @"\" + item.Name, destFilePath);
                                                   row[statusColumn] = "File trovato";
                                                   foundFile = true;
                                                   row[destinationPath] = destFilePath;
                                                   row[sourcePath] = item.Directory.FullName + @"\" + item.Name;
                                                   break;
                                               }
                                           }
                                       }
                                   }
                               }
                           }
                           #endregion SearchWithDictionary
                       }
                   }
                   else { Logger.LogInfo("One of the required input cells is empty"); }
                   if (foundFile == false)
                   {
                       row[sourcePath] = "File non trovato.";
                       row[statusColumn] = "File non trovato";
                       row[destinationPath] = "File non trovato";
                   }
               }
               outputFileName = FileUtils.AppendDateToFileName(outputFileName);
               return ExcelUtils.ExportDtToExcel(outputFilePath, dt, outputFileName);
           }
           else Logger.LogInfo("Required Date column was not found in the input file.");
            
            return "notok";
        }


        private void AddNewColumns(DataTable dt)
        {
            statusColumn = new DataColumn("Status");
            destinationPath = new DataColumn("Path");
            sourcePath = new DataColumn("SourcePath");

            dt.Columns.Add(destinationPath);
            dt.Columns.Add(sourcePath);
            dt.Columns.Add(statusColumn);
            
            DataRow firstRow = dt.Rows[0];

            firstRow[statusColumn] = "Stato di funzionamento";
            firstRow[sourcePath] = "Percorso del file sorgente";
            firstRow[destinationPath] = "Percorso del file di destinazione";
        }
        
        /// <summary>
        /// Build a possible file path and check if it exists
        /// </summary>
        public string BuildPossibleFPath(string extractedDate, string codClient, string rootDir)
        {
            string searchPath = "";
            DateTime date = DateTime.MinValue;
            if (extractedDate != "" && codClient != "")
            {
                date = DateTime.Parse(extractedDate);
                CultureInfo english = new CultureInfo("en-US");
                
                string month = english.DateTimeFormat.GetMonthName(date.Month).ToUpper();
                month = FileUtils.enCultureToItalian(month);
                //parse month
                string day = date.Day.ToString();
                string year = date.Year.ToString();
                string folderDate = date.ToString("dd'.'MM'.'yyyy ");
                searchPath = Path.Combine(rootDir , year + @"\" + month + " " + year + @"\" + folderDate + @"\" + codClient + ".pdf");
            }
            return searchPath;
        }

        public string BuildPossibleFPath1(string extractedDate, string codClient, string rootDir)
        {
            string searchPath = "";
            DateTime date = DateTime.MinValue;
            if (extractedDate != "" && codClient != "")
            {
                date = DateTime.Parse(extractedDate);
                CultureInfo english = new CultureInfo("en-US");

                string month = english.DateTimeFormat.GetMonthName(date.Month).ToUpper();
                month = FileUtils.enCultureToItalian(month);
                string day = date.Day.ToString();
                string year = date.Year.ToString();
                string folderDate = date.ToString("dd'_'MM'_'yyyy ");

                searchPath = Path.Combine(rootDir ,year + @"\" + month + " " + year + @"\" + folderDate + @"\" + codClient + ".pdf");
            }
            return searchPath;
        }

        public string BuildPossibleFPath2(string extractedDate, string codClient, string rootDir)
        {
            string searchPath = "";
            DateTime date = DateTime.MinValue;
            if (extractedDate != "" && codClient != "")
            {
                date = DateTime.Parse(extractedDate);
                CultureInfo english = new CultureInfo("en-US");

                string month = english.DateTimeFormat.GetMonthName(date.Month).ToUpper();
                month = FileUtils.enCultureToItalian(month);
                string day = date.Day.ToString();
                string year = date.Year.ToString();
                string folderDate = date.ToString("dd'.'MM'.'yyyy ");

                //make a check to see if rootDir lastC
                searchPath = Path.Combine(rootDir , year + @"\" + month + " " + year + @"\" +"ENI "+ folderDate + @"\" + codClient + ".pdf");
            }
            return searchPath;
        }

        public string BuildDestionationPath(string destinationPathRoot, string extractedDate, string contratto, string cod_vel,string ext)
        {
            string newPath = "";
            if (extractedDate != "" && contratto != "")
            {
                DateTime date = DateTime.Parse(extractedDate);
                CultureInfo english = new CultureInfo("en-US");
                string month = english.DateTimeFormat.GetMonthName(date.Month).ToUpper();
                month = FileUtils.enCultureToItalian(month);
                string day = date.Day.ToString();
                string year = date.Year.ToString();
                string folderDate = date.ToString("dd'.'MM'.'yyyy");
                newPath = Path.Combine(destinationPathRoot , year + @"\" + month + " " + year + @"\" + folderDate + @"\" + cod_vel + @"\" + contratto + ext);
            }
            return newPath;
        }

        public Dictionary<int, List<FileInfo>> BuildDictionary(string searchDir)
        {
            IEnumerable<FileInfo> filesList = null;
            Dictionary<int, List<FileInfo>> dict = new Dictionary<int, List<FileInfo>>();
            filesList = FileUtils.BuildFileList(new DirectoryInfo(searchDir));
            filesList = FileUtils.RemovePtlE(filesList);

            dict = FileUtils.BuildDictionaryFromFilesList(filesList);

            return dict;
        }

        bool CheckParentDirs(FileInfo debt, string cod_vel, string data)
        {
           //parent directory must match cod_vel
            if (FileUtils.ParseCodVel(debt.Directory.Name).ToString() == cod_vel )  
                if ( debt.Directory.Parent.Name.ToString() == FolderDateFormat(data)) //and parent of parent directory matches the input DATE
                return true;
            return false;
        }

        string FolderDateFormat(string input_file_date)
        {
            DateTime date = DateTime.MinValue;
            if (input_file_date != "")
            {
                date = DateTime.Parse(input_file_date);
                string month = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(date.Month).ToUpper();
                string day = date.Day.ToString();
                string year = date.Year.ToString();
                string folderDate = date.ToString("dd'.'MM'.'yyyy");
                return folderDate;
            }
            return "";
        }

        bool SearchFirstPathHardC(DataRow row)
        {
            string filePath = BuildPossibleFPath(row["DATA1"].ToString(), row["COD_VEL"].ToString(), searchPath1);//firstPath
            string filePathh = BuildPossibleFPath1(row["DATA1"].ToString(), row["COD_VEL"].ToString(), searchPath1);//firstPath
            string filePathhh = BuildPossibleFPath2(row["DATA1"].ToString(), row["COD_VEL"].ToString(), searchPath1);//firstPath
            if ((filePath != "" && File.Exists(filePath)))
            {
                string newFilePath = BuildDestionationPath(outputFilePath, row["DATA1"].ToString(), row["CONTRATTO"].ToString(), row["COD_VEL"].ToString(), ".pdf");
                if (newFilePath != "")
                {
                    FileUtils.CopyRenamed(filePath, newFilePath);
                    row[statusColumn] = "File trovato";
                    foundFile = true;
                    row[destinationPath] = newFilePath;
                    row[sourcePath] = filePath;
                    return true;
                }
            }
            if ((filePathh != "" && File.Exists(filePathh)))
            {
                string newFilePath = BuildDestionationPath(outputFilePath, row["DATA1"].ToString(), row["CONTRATTO"].ToString(), row["COD_VEL"].ToString(), ".pdf");
                if (newFilePath != "")
                {
                    FileUtils.CopyRenamed(filePathh, newFilePath);
                    row[statusColumn] = "File Trovato";
                    foundFile = true;
                    row[destinationPath] = newFilePath;
                    row[sourcePath] = filePathh;
                    return true;
                }
            }
            if ((filePathhh != "" && File.Exists(filePathhh)))
            {
                string newFilePath = BuildDestionationPath(outputFilePath, row["DATA1"].ToString(), row["CONTRATTO"].ToString(), row["COD_VEL"].ToString(), ".pdf");
                if (newFilePath != "")
                {
                    FileUtils.CopyRenamed(filePathhh, newFilePath);
                    row[statusColumn] = "File trovato";
                    foundFile = true;
                    row[destinationPath] = newFilePath;
                    row[sourcePath] = filePathhh;
                    return true;
                }
            }
            return false;
        }

        IEnumerable<FileInfo> SerializedIndex(string searchPath)
        {
            IEnumerable<FileInfo> filesInfo = null;
            FileStream fs = FileUtils.OpenFile(searchPath);//create if doesn't exists
            if (fs.Length == 0) //no serialization made yet; could include timestamp
            {
                filesInfo = FileUtils.BuildFileList(new DirectoryInfo(searchPath2)); //time consuming
                
                filesInfo = FileUtils.RemovePtlE(filesInfo); //remove pathsTooLong (because GetFiles doesn't thwrow PathToLongException :|)
                
                BinaryFormatter bf = new BinaryFormatter();
                try
                {
                    bf.Serialize(fs, filesInfo);
                }
                catch (Exception e)
                {
                    Logger.LogInfo(e.ToString());
                }
                finally
                {
                    fs.Flush();
                    fs.Close();
                }
            }
                if (!fs.CanRead)
                {
                    fs = FileUtils.OpenFile(ConfigurationManager.AppSettings["SerializedDictPath"]);//create if doesn't exists
                }

                BinaryFormatter bff = new BinaryFormatter();
                try
                {
                    //fs.Seek(0, SeekOrigin.Begin);
                    fs.Position = 0;
                    filesInfo = (IEnumerable<FileInfo>)bff.Deserialize(fs);//already serialized
                }
                catch (Exception e)
                {
                    Logger.LogInfo(e.ToString());
                }

                fs.Close();
            return filesInfo;
        }
    }
}
